module execution(/*AUTOARG*/
   // Outputs
   ex_o_data, ex_o_addr, ex_o_ctrl, ex_o_tag, ex_o_dst_reg,
   ex_o_branch_nt, regB_mem_o_valid,
   // Inputs
   clk, reset, ex_i_valueA, ex_i_valueB, ex_i_immediate, ex_i_tag,
   ex_i_dst_reg, ex_i_ctrl, regB_mem_i_valid, ex_i_hazard
   );

input clk;
input reset;
input [31:0] ex_i_valueA ;
input [31:0] ex_i_valueB ;
input [31:0] ex_i_immediate;
input [3:0] ex_i_tag;
input [4:0] ex_i_dst_reg;
input [5:0] ex_i_ctrl;
input [3:0] regB_mem_i_valid;
input ex_i_hazard;

output [31:0] ex_o_data;
output [31:0] ex_o_addr;
output [2:0] ex_o_ctrl;
output [3:0] ex_o_tag;
output [4:0] ex_o_dst_reg;
output [1:0] ex_o_branch_nt;
output [3:0] regB_mem_o_valid;

reg [31 :0] y_a;
reg [31 :0] ex_op2;
reg [1:0] branch_dec;

reg [31:0] ex_b_data;
reg [31:0] ex_b_addr;
reg [2:0] ex_b_ctrl;
reg [3:0] ex_b_tag;
reg [4:0] ex_b_dst_reg;
reg [1:0] ex_b_branch_nt;
reg [3:0] regB_mem_b_valid;

wire [1:0] alu_op;

assign ex_o_data = ex_b_data;
assign ex_o_addr = ex_b_addr;
assign ex_o_ctrl = ex_b_ctrl;
assign ex_o_tag = ex_b_tag;
assign ex_o_dst_reg = ex_b_dst_reg;
assign ex_o_branch_nt = ex_b_branch_nt;
assign regB_mem_o_valid = regB_mem_b_valid;

assign alu_op = ex_i_ctrl[4:3];

//------execution unit-------
always @(posedge clk or negedge reset)
begin
if(!reset)
begin
	ex_b_data = 0;
	ex_b_addr = 0;
	ex_b_ctrl = 0;
	ex_b_tag = 0;
	ex_b_dst_reg = 0;
	ex_b_branch_nt = 0;
	regB_mem_b_valid = 0;
end
else
	if(ex_i_hazard)
	begin
	if(alu_op == 2'b00)
		ex_b_data = ex_i_valueB;
	else
		ex_b_data = y_a;
	ex_b_addr = y_a;
	ex_b_ctrl = ex_i_ctrl[2:0];
	ex_b_tag = ex_i_tag;
	ex_b_dst_reg = ex_i_dst_reg;
	ex_b_branch_nt = branch_dec;
	regB_mem_b_valid = regB_mem_i_valid;
	end
end


//------alu----------------



always @(alu_op or ex_i_valueA or ex_op2)	
begin
if(alu_op == 2'b00 || alu_op == 2'b11)
	begin
	y_a <= ex_i_valueA + ex_op2;
	branch_dec <= 2'b00;
	end
else 
	if(alu_op == 2'b10)
		begin
		y_a <= ~(ex_i_valueA | ex_op2);
		branch_dec <= 2'b00;
		end
	else
		if(alu_op == 2'b01)
			if((ex_i_valueA - ex_op2) == 0)
				begin
				y_a <= ex_i_valueA - ex_op2;
				branch_dec <= 2'b01;
				end
			else
				branch_dec <= 2'b10;
		else
			y_a <= 0;
end

//-------selection of correct operands-----


always @(ex_i_valueB or ex_i_immediate or ex_i_ctrl[5])  //ex_i_ctrl[5] == aluSrc
begin
    case (ex_i_ctrl[5])
        0 : ex_op2 = ex_i_valueB;
        1 : ex_op2 = ex_i_immediate;
    endcase
end

endmodule

